﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Data.SqlClient;

namespace Autorun
{
	[Serializable]
	public class TaskConfigurationItem : MarshalByRefObject
	{
		private int _tskId;
		public string Caption;
		public readonly string Path;
		public readonly string AssemblyName;
		public readonly string ClassName;
		public readonly bool IsUsed;

		private StringDictionary _parameters;

		#region "Constructors"
		internal TaskConfigurationItem(DataRow row)
		{
			_tskId = (int)row["tskId"];
			Caption = row["tskCaption"].ToString();
			Path = row["tskPath"].ToString();
			AssemblyName = row["tskAssembly"].ToString();
			ClassName = row["tskClass"].ToString();

			IsUsed = ((int)row["tskUsage"] > 0);
		}

		internal TaskConfigurationItem(int taskId)
		{
			string query;
			DataTable dt;

			query = string.Format("SELECT * FROM tblTask WHERE tskId={0}", taskId);
			dt = ExecuteDataTable(query);
			if (dt.Rows.Count != 0)
			{
				_tskId = (int)dt.Rows[0]["tskId"];
				Caption = dt.Rows[0]["tskCaption"].ToString();
				Path = dt.Rows[0]["tskPath"].ToString();
				AssemblyName = dt.Rows[0]["tskAssembly"].ToString();
				ClassName = dt.Rows[0]["tskClass"].ToString();
			}
		}

		internal TaskConfigurationItem(string taskCaption, string assemblyName, string assemblyPath, string className)
		{
			string query;
			DataTable dt;

			// === Verify this task does not already exist =========================
			query = string.Format("SELECT * FROM tblTask WHERE tskPath{0} AND tskAssembly{1} AND tskClass{2} AND tskCaption{3}",
					SqlConvert.SqlStringOp(assemblyPath),
					SqlConvert.SqlStringOp(assemblyName),
					SqlConvert.SqlStringOp(className),
					SqlConvert.SqlStringOp(taskCaption));
			dt = ExecuteDataTable(query);

			if (dt.Rows.Count != 0)
			{
				_tskId = (int)dt.Rows[0]["tskId"];
				Caption = dt.Rows[0]["tskCaption"].ToString();
				Path = dt.Rows[0]["tskPath"].ToString();
				AssemblyName = dt.Rows[0]["tskAssembly"].ToString();
				ClassName = dt.Rows[0]["tskClass"].ToString();
			}
			else
			{
				_tskId = 0;
				Caption = taskCaption;
				Path = assemblyPath;
				AssemblyName = assemblyName;
				ClassName = className;
			}
		}

		#endregion

		#region "Procedures"
		public void Update(StringDictionary parameters)
		{
			string query;
			object recId;
			int count;

			if (Id != 0)
			{
				query = string.Format("UPDATE tblTask SET tskCaption={0} WHERE tskId={1}",
				SqlConvert.SqlString(Caption),
				Id);
				ExecuteNonQuery(query);
			}
			else
			{
				query = string.Format("INSERT INTO tblTask(tskCaption,tskPath,tskAssembly,tskClass) VALUES ({0},{1},{2},{3});SELECT @@IDENTITY FROM tblTask",
						SqlConvert.SqlString(Caption),
						SqlConvert.SqlString(Path),
						SqlConvert.SqlString(AssemblyName),
						SqlConvert.SqlString(ClassName));
				recId = ExecuteScalar(query);
				_tskId = int.Parse(recId.ToString());
			}

			// === Save the parameters =======================================
			if (parameters != null)
				foreach (DictionaryEntry item in parameters)
					if (_parameters.ContainsKey(item.Key.ToString()) == true)
						_parameters[item.Key.ToString()] = item.Value.ToString();

			// Flag the parameters as dirty
			query = string.Format("UPDATE tblConfig SET cfgDirty=1 WHERE fktskId={0}", _tskId);
			ExecuteNonQuery(query);

			foreach (DictionaryEntry item in Parameters)
			{
				query = string.Format("SELECT COUNT(*) FROM tblConfig WHERE fktskId={0} AND cfgKey={1}", _tskId, SqlConvert.SqlString(item.Key));
				count = (int)ExecuteScalar(query);
				if (count == 0)
					query = string.Format("INSERT INTO tblConfig(fktskId, cfgKey, cfgValue) VALUES ({0}, {1}, {2})",
							_tskId,
							SqlConvert.SqlString(item.Key),
							SqlConvert.SqlString(item.Value));
				else
					query = string.Format("UPDATE tblConfig SET cfgValue={2}, cfgDirty=0 WHERE fktskId={0} AND cfgKey={1}",
							_tskId,
							SqlConvert.SqlString(item.Key),
							SqlConvert.SqlString(item.Value));
				ExecuteNonQuery(query);
			}

			// Remove unused parameters
			query = string.Format("DELETE FROM tblConfig WHERE fktskId={0} AND cfgDirty=1", _tskId);
			ExecuteNonQuery(query);
		}
		#endregion

		#region "Properties"
		public int Id
		{
			get { return _tskId; }
		}

		// The facade must be build on the client-side, otherwise the dynamic library is not known
		//public StringDictionary Parameters
		//{
		//  get
		//  {
		//    if (_parameters == null)
		//      _parameters = BuildParametersFacade();

		//    return _parameters;
		//  }
		//}

		public StringDictionary Parameters
		{
			get
			{
				if (_parameters == null)
					_parameters = ScheduleManagement.Instance.GetTaskParameters(_tskId);

				//{
				//  string query;
				//  DataTable dt;

				//  _parameters = new StringDictionary();

				//  // Add the properties of the task
				//  query = string.Format("SELECT * FROM tblConfig WHERE fktskId={0}", _tskId);
				//  dt = ExecuteDataTable(query);
				//  foreach (DataRow dr in dt.Rows)
				//    _parameters.Add(dr["cfgKey"].ToString(), dr["cfgValue"].ToString());
				//}

				return _parameters;
			}
		}

		#endregion

		//#region "Facade Builder for the Parameters Property"
		//private StringDictionary BuildParametersFacade()
		//{
		//  StringDictionary rc;
		//  StringBuilder source;
		//  StringBuilder constructor;
		//  CSharpCodeProvider codeProvider;
		//  CompilerParameters compilerParameters;
		//  CompilerResults compilerResults;
		//  string query;
		//  DataTable dt;

		//  // ===============================================================
		//  // === Pre-Process                                             ===
		//  // ===============================================================
		//  source = new StringBuilder();
		//  constructor = new StringBuilder();
		//  codeProvider = new CSharpCodeProvider();
		//  compilerParameters = new CompilerParameters();

		//  // ===============================================================
		//  // === Process                                                 ===
		//  // ===============================================================
		//  // Prepare the construction definition
		//  constructor.AppendLine("public ParametersFacade() : base()");
		//  constructor.AppendLine("{");

		//  // Declare Namespace and usings
		//  source.AppendLine("using System;");
		//  source.AppendLine("using System.Collections.Specialized;");
		//  source.AppendLine("using System.ComponentModel;");
		//  source.AppendLine("namespace Autorun");
		//  source.AppendLine("{"); // Begin "namespace"

		//  // Declare class
		//  source.AppendLine("[Serializable]");
		//  source.AppendLine("public class ParametersFacade : StringDictionary");
		//  source.AppendLine("{"); // Begin "class"

		//  // Add the properties of the task
		//  query = string.Format("SELECT * FROM tblConfig WHERE fktskId={0}", _tskId);
		//  dt = ExecuteDataTable(query);
		//  foreach (DataRow dr in dt.Rows)
		//    AddPropertyToFacade(source, constructor, dr["cfgKey"].ToString(), dr["cfgValue"].ToString());

		//  // Terminate the constructor definition and add it to the class
		//  constructor.AppendLine("}");
		//  source.AppendLine(constructor.ToString());

		//  // Terminate the class and the namespace
		//  source.AppendLine("}"); // End "class"
		//  source.AppendLine("}"); // End "namespace"

		//  compilerParameters.ReferencedAssemblies.Add("System.dll");
		//  compilerParameters.GenerateExecutable = false;
		//  compilerParameters.GenerateInMemory = true;

		//  compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, source.ToString());
		//  if (compilerResults.Errors.Count != 0)
		//  {
		//    System.Diagnostics.Debug.WriteLine(source.ToString());
		//    source = new StringBuilder();
		//    foreach (CompilerError item in compilerResults.Errors)
		//      source.AppendLine(item.ToString());
		//    System.Windows.Forms.MessageBox.Show("Test");
		//    MessageBox.Show(source.ToString());
		//    compilerResults = null;
		//    rc = null;
		//  }
		//  else
		//    rc = (StringDictionary)compilerResults.CompiledAssembly.CreateInstance("Autorun.ParametersFacade");

		//  return rc;
		//}

		//private void AddPropertyToFacade(StringBuilder source, StringBuilder constructor, string name, string defaultValue)
		//{
		//  source.AppendLine("[Category(\"Configuration\")]");
		//  source.AppendFormat("\npublic string {0}", name);
		//  source.AppendLine("{");
		//  source.AppendLine("get");
		//  source.AppendLine("{");
		//  source.AppendFormat("\nif (this.ContainsKey(\"{0}\") == false)", name);
		//  source.AppendFormat("\nreturn \"{0}\";", defaultValue);
		//  source.AppendLine("else");
		//  source.AppendFormat("\nreturn this[\"{0}\"];", name);
		//  source.AppendLine("}");
		//  source.AppendLine("set");
		//  source.AppendLine("{");
		//  source.AppendFormat("\nthis[\"{0}\"] = value;", name);
		//  source.AppendLine("}");
		//  source.AppendLine("}");

		//  constructor.AppendFormat("\nthis[\"{0}\"] = \"{1}\";", name, defaultValue);
		//}

		//#endregion
		#region "Data Access Methods"
		private void ExecuteNonQuery(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				cmd.ExecuteNonQuery();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}
		}

		private object ExecuteScalar(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;
			object rc = null;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				rc = cmd.ExecuteScalar();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}

			return rc;
		}

		private DataTable ExecuteDataTable(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc.Tables.Count != 0 ? rc.Tables[0] : null;
		}

		private DataSet ExecuteDataSet(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc;
		}
		#endregion
	}

}
